/*
 * topological-hex, a program to compute combinatorial hexahedral meshes.
 *
 * Copyright (C) <2018> <Université catholique de Louvain (UCL), Belgique>
 *
 * List of the contributors to the development, description and complete
 * License: see LICENSE file.
 *
 * This program (topological-hex) is free software:
 * you can redistribute it and/or modify it under the terms
 * of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see COPYING file).  If not,
 * see <http://www.gnu.org/licenses/>.
 */

#ifndef QUEUE_H_
#define QUEUE_H_

#include <stdbool.h>
#include <stdint.h>
#include <pthread.h>

#include "types.h"
#include "utils.h"

/**
 * @defgroup concurrent Concurrent data structures
 *
 * Data-structures used to facilitate interactions between multiple threads.
 */

/**
 * @addtogroup concurrent
 * @{
 */

typedef struct concurrent_queue {
  pthread_mutex_t lock;
  pthread_cond_t empty_cond, full_cond;

  bool closed;
  uint32_t offset, size, capacity, element_size;

  ALIGNED void *data;
} concurrent_queue;

/**
 * Initializes a concurrent queue.
 *
 * @param num_slots Maximum number of elements stored in the queue.
 * @param element_size Size of each element stored in the queue.
 */
error_code concurrent_queue_init(concurrent_queue *queue, uint32_t num_slots,
                                 uint32_t element_size);

/**
 * Releases all memory used by a concurrent queue.
 */
void concurrent_queue_release(concurrent_queue *queue);

/**
 * Enqueues an element into the queue.
 *
 * @param data Pointer to data that will be copied into the queue.
 */
void concurrent_queue_push(concurrent_queue *queue, const void *data);

/**
 * Removes an element from the queue. If the queue is empty, waits until the
 * queue either closes or receives a new element.
 *
 * @param [out] data Pointer that will be filled
 *
 * @return True if an element was actually returned by this operation.
 */
bool concurrent_queue_pop(concurrent_queue *queue, void *data);

/**
 * Same as @ref concurrent_queue_pop, but does not wait if the queue is
 * empty. Instead, false is immediately returned.
 */
bool concurrent_queue_try_pop(concurrent_queue *queue, void *data);

/**
 * Closes the queue. Once this function has been called, all subsequent attempt
 * to retrieve an element from the queue will fail.
 */
void concurrent_queue_close(concurrent_queue *queue);

/**
 * @}
 */

#endif
